<?php


namespace App\Http\Controllers;

use App\Exceptions\CourseNotFoundException;
use App\Exceptions\CoursePaidException;
use App\Exceptions\OrderNotFoundException;
use App\Exceptions\OrderPaidException;
use App\Internals\CourseInternal;
use App\Jobs\OrderCanceledJob;
use App\Jobs\OrderNeedPayJob;
use App\Models\Order;
use App\Models\OrderItem;
use Illuminate\Support\Facades\DB;

class OrderController extends Controller
{
    /*
     * @api get /billing-api/orders 获取用户订单列表
     * @version 0.0.1
     * @group web
     *
     * @param query int [pageSize] 页数，默认15
     * @param query int [page] 页码，默认1
     *
     * @response 200 正常结果 {
     *  "code":0,
     *  "msg":"",
     *  "data":{
     * "total[总数]":9,"items[项]":[{"id[id]":9,"tradeNo[订单号]":"20180706081815449610","status[状态]":10,"paidAmount[实际付款]":"0.00","cover[封面图片]":"","issue[期数]":1}]
     *   }
     * }
     */
    public function index()
    {
        $this->validate($this->request, [
            "page" => "integer|min:1",
            "pageSize" => "integer|max:100|min:5"
        ]);
        $page = intval($this->request->input("page", 1));
        $pageSize = intval($this->request->input("pageSize", 15));
        $query = Order::where('user_id', $this->userId);
        $total = $query->count();
        $ordersObj = $query->orderBy('id', 'desc')->forPage($page, $pageSize)
            ->get();
        $items = [];
        if ($total) {
            /** @var Order $orderObj */
            foreach ($ordersObj as $index => $orderObj) {

                $orderItems = $orderObj->items();
                $item = [
                    'id' => $orderObj->getId(),
                    'name' => $orderObj->getName(),
                    'tradeNo' => $orderObj->getTradeNo(),
                    'status' => $orderObj->getStatus(),
                    'paidAmount' => $orderObj->getActualAmount(),
                    'paySurplusTime' => $orderObj->getPaySurplusTime(),
                    'cover' => '',
                    'courseLevel' => $orderItems->pluck('level'),
                    'createdAt' => date('Y-m-d', strtotime($orderObj->getCreatedAt())),
                ];
                if ($orderObj->getQuantity() === 1) {
                    $item['cover'] = CourseInternal::getCourseCover($orderItems->value('course_id'));
                }
                $items[] = $item;
            }
        }
        return $this->sendSuccessJson(['total'=>$total, 'items'=>$items]);
    }

    /*
     * @api post /billing-api/orders 创建订单
     * @version 0.0.1
     * @group web
     *
     * @param body array courseIds 课程ID
     *
     * @response 200 正常结果 {
     *  "code":0,
     *  "msg":"",
     *  "data":{}
     * }
     */
    public function store()
    {
        $this->validate($this->request, [
            'courseIds' => 'required|array',
            'name' => 'required|string'
        ]);
        $courseIds = $this->request->input('courseIds');
        $name = $this->request->input('name');
        $name = '小狐英语绘本 - ' . $name;
        // 检查是否存在
        $coursesInfo = CourseInternal::getCourseByCourseIds($courseIds);
        $quantity = count($courseIds);
        if (count($coursesInfo) != $quantity) {
            throw new CourseNotFoundException();
        }
        // 检查是否购买
        foreach ($courseIds as $courseId) {
            if (OrderItem::ofUserPaid($this->userId)->where('course_id', $courseId)->exists()) {
                $level = $coursesInfo[$courseId]['level'];
                $msg = "您已经购买level {$level}课程，无须重复购买";
                throw new CoursePaidException($msg);
            }
        }

        try {
            $totalAmount = 0;
            $discountAmount = 0;
            foreach ($coursesInfo as $courseInfo) {
                $totalAmount += $courseInfo['price'];
                $discountAmount += $courseInfo['discountPrice'];
            }
            $actualAmount = bcsub($totalAmount, $discountAmount, 2);
            DB::beginTransaction();
            $orderObj = new Order();
            $orderObj->setUserId($this->userId);
            $orderObj->setName($name);
            $orderObj->setQuantity($quantity);
            $orderObj->setDiscountAmount($discountAmount);
            $orderObj->setActualAmount($actualAmount);
            $orderObj->setTotalAmount($totalAmount);
            $orderObj->setStatus(Order::ORDER_STATUS['need_pay']);
            $orderObj->save();
            foreach ($coursesInfo as $courseInfo) {
                $orderItemObj = new OrderItem();
                $orderItemObj->setUserId($this->userId);
                $orderItemObj->setOrderId($orderObj->getId());
                $orderItemObj->setCourseId($courseInfo['id']);
                $orderItemObj->setLevel($courseInfo['level']);
                $orderItemObj->setPrice($courseInfo['price']);
                $orderItemObj->setDiscountPrice($courseInfo['discountPrice']);
                $orderItemObj->setStatus(Order::ORDER_STATUS['need_pay']);
                $orderItemObj->save();
            }
            // 支付service
            $result = app('wxPay')->createOrder($orderObj->getTradeNo(), $this->userId, $name, $actualAmount);
            $result['orderId'] = $orderObj->getId();
            DB::commit();
        } catch (\PDOException $e) {
            DB::rollBack();
            throw new OrderPaidException();
        }
        return $this->sendSuccessJson($result);
    }

    /*
     * @api get /billing-api/orders/{orderId}/pay 重新支付
     * @version 0.0.1
     * @group web
     *
     * @response 200 正常结果 {
     *  "code":0,
     *  "msg":"",
     *  "data":{}
     * }
     */
    public function pay($orderId)
    {
        /** @var Order $orderObj */
        $orderObj = Order::find($orderId);
        if (!$orderObj) {
            throw new OrderNotFoundException();
        }
        // 判断订单状态
        if (!$orderObj->checkPayStatus()) {
            throw new OrderPaidException();
        }
        // 检查是否购买
        $orderItems = $orderObj->items()->get();
        /** @var OrderItem $orderItem */
        foreach ($orderItems as $orderItem) {
            if (OrderItem::ofUserPaid($this->userId)->where('course_id', $orderItem->getCourseId())->exists()) {
                $level = $orderItem->getLevel();
                $msg = "您已经购买level {$level}课程，无须重复购买";
                throw new CoursePaidException($msg);
            }
        }
        // 支付service
        $result = app('wxPay')->createOrder($orderObj->getTradeNo(), $this->userId, $orderObj->getName(), $orderObj->getActualAmount());
        return $this->sendSuccessJson($result);
    }

    /*
     * @api post /billing-api/orders/{orderId}/cancel 取消订单
     * @version 0.0.1
     * @group web
     *
     * @param path int orderId 订单ID
     *
     * @response 200 正常结果 {
     *  "code":0,
     *  "msg":"",
     *  "data":{
     *  }
     * }
     */
    public function cancel($orderId)
    {
        /** @var Order $orderObj */
        $orderObj = Order::where('id', $orderId)->where('user_id', $this->userId)->first();
        if (!$orderObj) {
            throw new OrderNotFoundException();
        }
        if (!$orderObj->checkCancelStatus()) {
            throw new OrderNotFoundException();
        }
        $orderObj->setStatus(Order::ORDER_STATUS['canceled']);
        $orderObj->save();
        $this->dispatch(new OrderCanceledJob(
            $this->userId,
            $orderObj->getTradeNo(),
            $orderObj->getName(),
            $orderObj->getActualAmount(),
            $orderObj->items()->pluck('level')->toArray()
        ));
        return $this->sendSuccessJson();
    }

    /*
     * @api post /billing-api/orders/{orderId}/unpay 订单未支付
     * @version 0.0.1
     * @group web
     *
     * @param path int orderId 订单ID
     *
     * @response 200 正常结果 {
     *  "code":0,
     *  "msg":"",
     *  "data":{
     *  }
     * }
     */
    public function unPay($orderId)
    {
        /** @var Order $orderObj */
        $orderObj = Order::where('id', $orderId)->where('user_id', $this->userId)->first();
        if (!$orderObj) {
            throw new OrderNotFoundException();
        }
        if ($orderObj->getStatus() == Order::ORDER_STATUS['need_pay']) {
            $this->dispatch(new OrderNeedPayJob(
                $this->userId,
                $orderObj->getTradeNo(),
                $orderObj->getName(),
                $orderObj->getActualAmount(),
                date('Y-m-d H:i:s', strtotime($orderObj->getCreatedAt())),
                $orderObj->items()->pluck('level')->toArray()
            ));
        }
        return $this->sendSuccessJson();
    }
}
